package com.abcd1234.zkPerf;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import java.io.IOException;

public class ZkClient implements Watcher, Runnable {
    // ID
    private String id = "/example";
    // ZooKeeper连接实例
    private final ZkLink zkLink;
    // 被监视的节点路径
    private String watchNodePath;
    // 总测试次数
    private int totalTestTimes;
    // 通过的测试次数
    private int passTimes;

    // 构造函数，初始化ZooKeeper连接
    public ZkClient(String zkHost) throws IOException {
        zkLink = new ZkLink(zkHost, this);
    }

    public ZkClient(String zkHost, String id) throws IOException {
        this.id = id;
        zkLink = new ZkLink(zkHost, this);
    }

    // 实现Watcher接口的方法，处理来自ZooKeeper的事件
    @Override
    public void process(WatchedEvent event) {
        System.out.println("接收到事件: " + event);
        // 检查事件类型
        if (event.getType() == Event.EventType.None) {
            // 处理连接状态事件
            switch (event.getState()) {
                case SyncConnected:
                    // 已同步连接
                    break;
                case Disconnected:
                    // 已断开连接
                    break;
            }
        } else {
            // 如果事件路径与监视路径相同，重新设置监视
            if (watchNodePath != null && event.getPath().equals(watchNodePath)) {
                zkLink.watchNode(watchNodePath, true);
            }
        }
    }

    // 设置节点的数据
    public void setNodeData(String nodePath, String data) throws KeeperException, InterruptedException {
        zkLink.setNodeData(nodePath, data);
    }

    // 创建一个节点并返回路径
    public String createNode(String nodePath, String data, CreateMode createMode) throws KeeperException, InterruptedException {
        return zkLink.createNode(nodePath, data, createMode);
    }

    // 删除一个节点
    public void deleteNode(String nodePath) throws InterruptedException, KeeperException {
        zkLink.deleteNode(nodePath, -1);
    }

    // 监视一个节点，如果监视成功则更新监视路径
    public boolean watchNode(String nodePath) {
        boolean watched = zkLink.watchNode(nodePath, true);
        if (watched) {
            watchNodePath = nodePath;
        }
        return watched;
    }

    // 关闭ZooKeeper连接
    public void close() throws InterruptedException {
        zkLink.close();
    }

    // 主函数，用于测试ZkClient的功能
    public static void main(String[] args) {
        try {
            ZkClient zkClient = new ZkClient("localhost:2181");
            String nodePath = "/exampleNode_0";
            zkClient.createNode(nodePath, "初始数据", CreateMode.PERSISTENT);
            zkClient.setNodeData(nodePath, "更新后的数据");
            System.out.println(zkClient.watchNode(nodePath) ? "节点活跃" : "节点不存在");
            zkClient.deleteNode(nodePath);
            System.out.println(zkClient.watchNode(nodePath) ? "节点活跃" : "节点不存在");
            zkClient.close();
        } catch (IOException | KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 实现Runnable接口的run方法，进行性能测试
    @Override
    public void run() {
        totalTestTimes = 1000; // 设置总测试次数
        passTimes = 0; // 初始化通过次数
        boolean existing = true; // 初始通过

        for (int i = 0; i < totalTestTimes; i++) {
            try {
                String nodePath = this.id + "_" + i;
                zkLink.createNode(nodePath, "", CreateMode.EPHEMERAL);
                String data = String.format("%s0x%06d", watchNodePath, i);
                zkLink.setNodeData(nodePath, data);
                if (zkLink.watchNode(nodePath, existing)) {
                    passTimes++; // 如果监视成功，通过次数加一
                } else {
                    existing = false;
                }
                zkLink.deleteNode(nodePath, -1);
            } catch (KeeperException | InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 计算通过率并打印测试结果
        double passRate = (double) passTimes / totalTestTimes * 100;
        System.out.printf("测试完成。总测试次数: %d, 通过次数: %d, 通过率: %.2f%%\n",
                totalTestTimes, passTimes, passRate);
    }
}
